#include "lcd_1602.h"
#include "delay.h"

const uint16_t WAIT = 40; //判断液晶忙时写入数据的等待时长，可能不同的硬件有所不同。

void LCD1602_GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); //使能PB,PD端口时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//IO口速度为50MHz
    GPIO_Init(GPIOA, &GPIO_InitStructure);				//初始化GPIOA0~7

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//IO口速度为50MHz
    GPIO_Init(GPIOB, &GPIO_InitStructure);				//初始化GPIB15,14,13
}

/* 等待液晶准备好 */
void LCD1602_Wait_Ready(void)
{
    LCD_RS_Clr();
    LCD_RW_Set();
    LCD_EN_Set();
    DATAOUT(0xFF);
    Delay_Us(WAIT);
    while((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_7) & 0x80) == 0x80); //bit7等于1表示液晶正忙，重复检测直到其等于0为止
    LCD_RW_Set();
    LCD_EN_Clr();
}

/* 向LCD1602液晶写入一字节命令，cmd-待写入命令值 */
void LCD1602_Write_Command(u8 cmd)
{
    LCD1602_Wait_Ready();
    LCD_RS_Clr();
    LCD_RW_Clr();
    DATAOUT(cmd);
    LCD_EN_Set();
    LCD_EN_Clr();
}

/* 向LCD1602液晶写入一字节数据，dat-待写入数据值 */
void LCD1602_Write_Data(u8 dat)
{
    LCD1602_Wait_Ready();
    LCD_RS_Set();
    LCD_RW_Clr();
    DATAOUT(dat);
    LCD_EN_Set();
    LCD_EN_Clr();
}

/* 清屏 */
void LCD1602_ClearScreen(void)
{
    LCD1602_Write_Command(0x01);
}

/* 设置显示RAM起始地址，亦即光标位置，(x,y)-对应屏幕上的字符坐标 */
void LCD1602_Set_Cursor(u8 x, u8 y)
{
    u8 addr;

    if (y == 0)
        addr = 0x00 + x;
    else
        addr = 0x40 + x;
    LCD1602_Write_Command(addr | 0x80);
}

/* 在液晶上显示字符串，(x,y)-对应屏幕上的起始坐标，str-字符串指针 */
void LCD1602_Show_String(u8 x, u8 y, u8 *str)
{
    LCD1602_Set_Cursor(x, y);
    while(*str != '\0')
    {
        LCD1602_Write_Data(*str++);
    }
}

/* 初始化1602液晶 */
void LCD1602_Init(void)
{
    LCD1602_Write_Command(0x38);	//16*2显示，5*7点阵，8位数据口
    LCD1602_Write_Command(0x0c);	//开显示，光标关闭
    LCD1602_Write_Command(0x06);	//文字不动，地址自动+1
    LCD1602_Write_Command(0x01);	//清屏
}
/*
*常用命令：0x38:16*2显示，5*&点阵显示字符，8位数据;指令执行时间40us
*          0x0C:开显示，关光标   40us
*          0x08:关显示，关光标   40us
*          0x0D:字符闪烁，关光标，接着设定位置，闪烁周期0.4ms左右
*          0x0F:字符闪烁，开光标
*          0x06:写完数据自动右移光标，普通情形，从左向右显示  40us
*          0x04:写完数据自动左移光标，可以从右向左显示  40us
*          0x01:清除显示内容，即清屏  1.64ms
*          0x02:使光标还回起始位置   1.64ms
*          0x18:屏幕上所有字符同时左移一格，适合滚动显示 40us
*          0x1C:屏幕上所有字符同时右移一格，适合滚动显示 40us
*/
